
#include <list>
#include <deque>
#include <mutex>
#include <condition_variable>
#include <atomic>
using namespace std;

#ifndef SYNC_QUEUE_1_HPP
#define SYNC_QUEUE_1_HPP
namespace zhb
{
    const int MaxTaskCount = 500;

    template <class T>
    class SyncQueue
    {
        std::deque<T> m_queue;

        std::mutex mtx;
        std::condition_variable notEmpty; // 消费者
        std::condition_variable notFull;  // 生产者

        int m_maxSize;
        atomic_bool m_needStop; // true  stop

        template <class F>
        void Add(F &&task)
        {

            std::unique_lock<std::mutex> lock(mtx);

            while (isFull() && !m_needStop)
            {
                notFull.wait(lock);
            }
            if (!m_needStop)
            {
                m_queue.emplace_back(std::forward<F>(task));
            }

            notEmpty.notify_all();
        }

    public:
        SyncQueue(int maxsize = MaxTaskCount) : m_maxSize(maxsize), m_needStop(false) {}

        ~SyncQueue() { Stop(); };
        SyncQueue(const SyncQueue &) = delete;
        SyncQueue &operator=(const SyncQueue &) = delete;
        void Put(const T &task) { Add(task); }
        void Put(T &&task) { Add(std::forward<T>(task)); }
        void Take(T &task)
        {
            std::unique_lock<std::mutex> lock(mtx);

            notEmpty.wait(lock, [this]
                          { return m_needStop || !isEmpty(); }); // 真 跳出

            if (!m_needStop)
            {
                task = m_queue.front();
                m_queue.pop_front();
            }
            notFull.notify_all();
        }
        // void Take(std::deque<T>&queue);

        void Stop()
        {
            m_needStop = true;
            notEmpty.notify_all();
            notFull.notify_all();
        }
        bool isEmpty() { return m_queue.empty(); }
        bool isFull() { return m_queue.size() >= m_maxSize; }

        size_t Size() const
        {
            std::lock_guard<std::mutex> lock(mtx);
            return m_queue.size();
        }
    };

} // namespace zhb

#endif